/*
 *    Copyright (c) 2018-2025, shenghua All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: shenghua
 */

package com.chen.base.module.redis.aop;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.chen.base.module.redis.annotation.Lock;
import com.chen.base.module.redis.inter.LockFunctional;
import com.chen.base.module.redis.service.DistributedLock;
import com.chen.base.utils.JoinPointUtil;
import com.chen.base.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author 陈锦龙
 * @since 2022/3/16 16:12
 */
@Aspect
@Component
@Slf4j
@Order(0)
public class LockAop {

	@Around("@annotation(lock)")
	public Object lockAround(ProceedingJoinPoint point, Lock lock) throws Throwable {
		Object obj;
		LockFunctional lockObj = null;

		try {
			// 加锁
			DistributedLock lockImpl = (DistributedLock) SpringContextHolder.getBean(lock.actionClass());
			lockObj = lockImpl.lock(key(point, lock), lock.expire());
			Assert.notNull(lockObj, lock.msg());

			obj = point.proceed();
		} finally {
			if (lockObj != null){
				lockObj.unLock();
			}
		}

		return obj;
	}

	/**
	 * 根据SPEL表达式读取加锁的key
	 */
	private String key(JoinPoint point, Lock lock){
		Object keyObj = JoinPointUtil.getSpelVa(point, lock.value());
		Assert.isFalse(StrUtil.isBlankIfStr(keyObj),"Lock Key 禁止为空!");
		return lock.prefixKey() + keyObj;
	}
}
